# -*- coding: ISO-8859-1 -*-
"""Various biblib utilities

"""

# Copyright (c) 2007 Kjell Magne Fauske
# See LICENSE for details.



import time, random, md5, re, string
from sets import Set

# extract number
_numext_re = re.compile(r"\d+")

_strext_re = re.compile(r"[a-zA-Z]+")
_strext2_re = re.compile(r"[a-zA-Z][a-zA-Z]+")
# extract pages
_pagesext_re = re.compile(r"(\d+)[ ]*-[ ]*(\d+)")
# match pages like I-528 - I-535 Vol.1
_pagesext2_re = re.compile(r"(?:\w+-)(\d+)[ ]*-[ ]*(?:\w+-)(\d+)")
_cap_re = re.compile(r"([A-Z][A-Z]+)")
_cap2_re = re.compile(r"^([A-Z]+)")

special_chars = ['%','&']#,'{','}']
special_chars_escape = [r'\%',r'\&'] #,r'\{',r'\}']

def getfirst(d, keys, default = None):
    for key in keys:
        item = d.get(key,None)
        if item :
            return (item, Set([key]))
    return (default, Set())

def getall(d, keys, default = None):
    items = []
    used_fields = Set()
    for key in keys:
        item = d.get(key,None)
        if item:
            if type(item) == list:
                items.extend(item);
            else:
                items.extend([item]);
            used_fields.add(key)
    return (items, used_fields)

def mreplace(s, chararray, newchararray):
    for a, b in zip(chararray, newchararray):
        s = s.replace(a, b)
    return s

def extNum(data):
    """Extract numeric part of a string

    Returns an empty string if no match is found.
    """
    if not data: return ''
    d = _numext_re.findall(data)
    if d:
        return d[0]
    else:
        return ''

def extNums(data):
    """Extract numeric part of a string

    """
    if not data: return ''
    d = _numext_re.findall(data)
    if d:
        return d
    else:
        return ''

def extStr(data):
    """Extract the 'string' [a-z] part of a string

    Returns an empty string if no match is found.
    """
    if not data: return ''
    d = _strext_re.findall(data)
    if d:
        return d[0]
    else:
        return ''

def extStrs(data):
    """Extract the 'string' [a-z] part of a string

    Returns an empty string if no match is found.
    """
    if not data: return ''
    d = _strext2_re.findall(data)
    if d:
        return d
    else:
        return ''

def extPages(data):
    if not data: return ''
    d = _pagesext_re.findall(data)
    if d:
        return d[0]
    d = _pagesext2_re.findall(data)
    if d:
        return d[0]

    else: return ''

def extYear(data):
    if data:
        d = re.findall(r'\d\d\d\d',data)
        if d:
            return d[0]
    return ''

def openAnything(source):
    '''URL, filename, or string --> stream

    This function lets you define parsers that take any input source
    (URL, pathname to local or network file, or actual data as a string)
    and deal with it in a uniform manner.  Returned object is guaranteed
    to have all the basic stdio read methods (read, readline, readlines).
    Just .close() the object when you're done with it.

    From the excelent Dive into Python book: http://www.diveintopython.org
    '''

    # try to open with urllib (if source is http, ftp, or file URL)
    import urllib
    try:
        return urllib.urlopen(source)
    except (IOError, OSError):
        pass

    # try to open with native open function (if source is pathname)
    try:
        return open(source)
    except (IOError, OSError):
        pass

    # treat source as string
    import StringIO
    return StringIO.StringIO(str(source))

def uuid( *args ):
    """Generates a universally unique ID.
    Any arguments only create more randomness.
    """
    t = long( time.time() * 1000 )
    r = long( random.random()*100000000000000000L )
    a = random.random()*100000000000000000L
    data = str(t)+' '+str(r)+' '+str(a)+' '+str(args)
    data = md5.md5(data).hexdigest()
    return hash(data)

def normalizeName(name):
    """Convert name to the format Lastname, Initials

    Names are assumed to be in the BibTeX format:
        Given names Surname
        Surname, Given names
    """
    idx = name.find(',')
    if idx < 0:
        words = name.split()
        lastname = words[-1]
        given_names = words[:-1]
    else:
        words = name.replace(',',' ').split()
        lastname = words[0]
        given_names = words[1:]

    s = " "
    initials = s.join([gn[0]+'.' for gn in given_names])
    return lastname+', '+initials

def formatFirstnameFirst(name):
    """Convert name to the format Firstname Lastname

    Names are assumed to be in the BibTeX format:
        Given names Surname
        Surname, Given names
    """
    idx = name.find(',')
    if idx < 0:
        # assume that name already has the Firstname Lastname format
        return name
    else:
        words = name.split(',')
        lastname = words[0]
        given_names = " ".join(words[1:])
        return given_names.strip() + ' ' +lastname.strip()


def getDOI(url):
    """Extract DOI number from an url of the type dx.doi.org/..."""
    pass

def renameKey(d, oldkey, newkey):
    d[newkey] = d[oldkey]
    del d[oldkey]

def embraceUppercase(string):
    """Put braces around uppercase words in string

    Ignores strings that start with '@'
    """
    if string:
        if string[0] == '@':
            return string
        else:
            return _cap_re.sub(r'{\1}', string)
    else:
        return string

def embraceUppercaseLetters(text):
    """Put braces around uppercase letters that start a word

    Braces are not put around the letter that starts a sentence.
    Ignores strings that start with '@'.

    >>> embraceUppercaseLetters('@Ignore Me')
    '@Ignore Me'
    >>> embraceUppercaseLetters('Test String IEEE IEEEXplore')
    'Test {S}tring {IEEE} {IEEEX}plore'
    """
    if text:
        if text[0] == '@':
            return text
        else:
            pieces = text.split()
            res = pieces[0]
            # Iterate over each word. Ignore the first.
            for word in pieces[1:]:
                # TODO: Recognize scandinavian characters
                word =_cap2_re.sub(r'{\1}', word)
                res += ' '+word
            return res

    else:
        return string

def escapeTeXChars(string):
    """Escape the special LaTeX-cahrs %{}_^"""
    return mreplace(string, special_chars, special_chars_escape)

def printDict(d):
    for key, value in d.iteritems():
        print "%s : %s" % (str(key),str(value))

nocapsl = ['and','or','of','for','the','in','a','an','on','by',
    'at', 'to','but','nor','as']
keepcapsl = ['IEEE','SNAME','ACM','IEE','IEEE-ACM','ISA','IGPL','AI','USA']

def capwords(string, nocaplist = nocapsl, keepcaps = keepcapsl):
    """Capitalize each word in a string

    >>> capwords('Diagnosis and fault tolerant control')
    'Diagnosis and Fault Tolerant Control'
    """
    words = string.split()
    for idx,word in enumerate(words):
        if not word in keepcaps:
            word = word.lower()
            if idx == 0 or word not in nocaplist:
                word = word.capitalize()

            words[idx] = word
    return " ".join(words)

def capwords2(text, nocaplist = nocapsl):
    """Capitalize each word in a string

    Words that start with uppercase letters or are part of the nocaplist,
    are not converted.

    >>> capwords2('Diagnosis and IEEE tolerant IV control')
    'Diagnosis and IEEE Tolerant IV Control'
    >>> capwords2('diagnosis and IEEE tolerant in control')
    'Diagnosis and IEEE Tolerant in Control'
    >>> capwords2('Spectral-feature of model-based methods')
    'Spectral-Feature of Model-Based Methods'
    >>> capwords2('A 3D method for "SHA-ha"')
    'A 3D Method for "SHA-ha"'
    """
    words = text.split()
    lowercase = string.lowercase
    letters = string.letters
    for idx,word in enumerate(words):
        if word[0] not in letters:
            continue
        nwords = word.split('-')
        if len(nwords)>1:
            word = "-".join([nword.capitalize() for nword in nwords])
            words[idx] = word
        elif word[0] in lowercase:
            if word not in nocaplist:
                word = word.capitalize()
                words[idx] = word
    return " ".join(words)

def _test():
    import doctest
    doctest.testmod()

if __name__ == "__main__":
    _test()


